package ee.fj.http;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.imageio.ImageIO;

public class Response {
	private final String NEW_LINE = "\r\n";
	private final String CONNECTION_CLOSE = "Connection: close";
	private static enum HEADER {
		TYPE("Content-Type: "),
		LENGTH("Content-Length: "),
		CHARSET("charset=");
		private final String val;
		private HEADER(String val) {
			this.val = val;
		}
	}
 
	public static enum TYPE {
		HTML("text/html;"),
		CSS("text/css;"),
		JS("application/javascript;");
		public final String val;
		private TYPE(String val) {
			this.val = val;
		}
	}

	public static enum STATUS {
		OK("HTTP/1.1 200 OK"),
		ERROR("HTTP/1.1  500 Internal Server Error"),
		SERVER("Computer remote control HTTPServer");
		public final String val;
		private STATUS(String val) {
			this.val = val;
		}
	}

	private final DataOutputStream out;
	private TYPE type = TYPE.HTML;
	private String strType = null;
	private Charset charset = Charset.forName("utf-8");
	private boolean isStarted = false;
	private StringBuffer buffer;
	private final String serverName;

	public Response(DataOutputStream out, String serverName) {
		this.out = out;
		this.serverName = serverName;
	}

	public void setCharset(String charset) { this.setCharset(Charset.forName(charset)); }
	public void setCharset(Charset charset) { this.charset = charset; }
	public void setResponseType(TYPE type) { this.type = type; }

	public synchronized StringBuffer getWriter() {
		if (buffer == null)
			buffer = new StringBuffer();
		return buffer;
	}


	public void close() throws IOException {
		try {
			setHeader(true, STATUS.OK);
		} finally {
			try {
				if (this.buffer != null) {
					out.writeBytes(this.buffer.toString());
				}
			} finally {
				try {
					this.out.flush();
				} finally {
					this.out.close();
				}
			}
		}
	}

	public void setHeader(boolean setSize, STATUS status) throws IOException {
		if (isStarted)
			return;
		isStarted = true;
		out.writeBytes(status.val);
		out.writeBytes(NEW_LINE);
		out.writeBytes(HEADER.TYPE.val);
		out.writeBytes(strType != null ? strType : (type.val + HEADER.CHARSET.val + charset.displayName()));
		out.writeBytes(NEW_LINE);
		out.writeBytes(serverName);
		out.writeBytes(NEW_LINE);
		if (setSize && buffer != null) {
			out.writeBytes(HEADER.LENGTH.val + buffer.length());
			out.writeBytes(NEW_LINE);
		}
		out.writeBytes(CONNECTION_CLOSE);
		out.writeBytes(NEW_LINE);
		out.writeBytes(NEW_LINE);
	}

	public void stream(TYPE type, InputStream in) throws IOException {
		setResponseType(type);
		setHeader(false, STATUS.OK);
		BufferedReader inn = new BufferedReader(new InputStreamReader(in));
		StringBuffer writer = getWriter();
		try {
			char[] b = new char[1024];
			int len=inn.read(b);
	        while (len != -1) {
	        	writer.append(b, 0, len);
	        	len=inn.read(b);
	        }
		} finally {
			inn.close();
		}
	}

	public void stream(String type, BufferedImage image) throws IOException {
		strType = "image/"+type;
		setHeader(false, STATUS.OK);
		ImageIO.write(image, type, out);
	}

	public void stream(String type, InputStream in) throws IOException {
		strType = type;
		setHeader(false, STATUS.OK);
		try {
			byte[] b = new byte[1024];
			int len=in.read(b);
	        while (len != -1) {
	        	this.out.write(b, 0, len);
	        	len=in.read(b);
	        }
		} finally {
			in.close();
		}
	}
}
